;;;    lambda-tube (λ-tube) - A youtube search API and application in scheme.
;;;    Copyright (C) 2008  Abhishek Mishra
;;;
;;;    This program is free software: you can redistribute it and/or modify
;;;    it under the terms of the GNU General Public License as published by
;;;    the Free Software Foundation, either version 3 of the License, or
;;;    (at your option) any later version.

;;;    This program is distributed in the hope that it will be useful,
;;;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;;    GNU General Public License for more details.

;;;    You should have received a copy of the GNU General Public License
;;;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

;;;    The scheduler module allows the program to run multiple actions in the background,
;;;    while letting the user work.

(module lt-scheduler mzscheme
  (require (lib "class.ss"))
  
  (provide init-scheduler 
           get-event-types 
           add-task-to-scheduler 
           scheduler-task<%> 
           generic-task%)
  
  ;;; this is the scheduler global
  (define *scheduler* '())
  
  (define *scheduler-sleep-time* 2)
  
  ;;; event types
  (define *event-types* '())
  
  ;;; init the scheduler
  (define (init-scheduler)
    (set! *scheduler* '())
    (set-scheduler-run))
  
  (define (set-scheduler-run)
    (thread (lambda () 
              (sleep *scheduler-sleep-time*) 
              (if (not (eq? *scheduler* '()))
                  (begin 
                    (update-tasks *scheduler* '())
                    (run-tasks *scheduler*)))
              (set-scheduler-run))))
  
  (define (run-tasks s)
    (if (eq? s '())
        #f
        (let* ((t (car s)) (d (send t get-delay)))
          (if (eq? d 0)
              (thread (lambda () (send t execute))))
          (run-tasks (cdr s)))))
  
  (define (update-tasks s u)
    (if (eq? s '())
        (set! *scheduler* u)
        (let* ((t (car s)) (d (send t get-delay)))
          (if (> d 0)
              (begin
                (send t set-delay! (- d *scheduler-sleep-time*))
                (update-tasks (cdr s) (append u (list t)))))
          (if (eq? d 0)
              (begin 
                (update-tasks (cdr s) u)))
          )))
  
  (define (get-event-types)
    *event-types*)
  
  (define (add-task-to-scheduler t)
    (set! *scheduler* (append *scheduler* (list t))))
  
  ;;; the scheduler task interface
  (define scheduler-task<%> (interface () execute set-delay! get-delay get-name))
  
  ;;; the generic task
  (define generic-task%
    (class* object% (scheduler-task<%>)
      (public set-delay! get-delay get-name)
      
      (pubment execute)
      
      (init-field (delay #f))
      (init-field (name "no-name"))
      
      (define (execute)
        (inner (void) execute)
        #f)
      
      (define (set-delay! d)
        (if (or (eq? d #f) (not (< d 0)))
            (set! delay d)
            (set! delay 0)))
      
      (define (get-delay)
        delay)
      
      (define (get-name)
        name)
      
      (super-new)
      ))
  )
